home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.04 Apr 95 / Performance / Fractal 4 / FractalEngine.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-13  |  13.5 KB  |  583 lines  |  [TEXT/MPS ]

  1. /*    
  2.     File:        FractalEngine.c
  3.  
  4.     Used to build:    “Fractal 4”
  5.     
  6.     Written by:        Jim Cathey            July 1985
  7.                     Eric Traut            November 1994
  8.  
  9.     Description:
  10.         The following code implements a “Fractal Contour” generating
  11.         program. See comments in the file “FractalMain.c” for more
  12.         information.
  13.         
  14.         The code in this file implements the fractal-generating
  15.         and plotting portion of the program.
  16. */
  17.  
  18.  
  19. #include <Quickdraw.h>
  20. #include <ToolUtils.h>
  21.  
  22. #include <stdlib.h>
  23.  
  24. #include "Fractal.h"
  25.  
  26. /* Functions defined within this file */
  27. double RandomDouble(void);
  28. void CalcXs(short len, short incr, short sk);
  29. void CalcYs(short len, short incr, short sk);
  30. void CalcDiagonals(short len, short incr, short sk);
  31. short GetZValue(short x, short y);
  32. void SetZValue(short d, short x, short y);
  33. void SeaLevel(short *newx, short *newy, short *newz);
  34. short ScaleValue(short base, short numer, short denom);
  35. void DoPlot(short xindex, short yindex);
  36. void PlotTo(short x, short y, short z);
  37. void Rotate(short *x, short *y);
  38. void TiltDown(short *x, short *z);
  39. void DrawLine(short x, short y);
  40. void Cordic(short *x, short *y, short scale, short count);
  41. void ScaledMoveTo(short x, short y);
  42. void ScaledLineTo(short x, short y);
  43. void SetLineColor(short colorCode);
  44. void MoveToOffscreen(short x, short y);
  45. void LineToOffscreen(short x, short y);
  46. void LineXOffscreen(short startX, short startY, short endX, short endY);
  47. void LineYOffscreen(short startX, short startY, short endX, short endY);
  48.  
  49. /* Global variables */
  50. short             gMaxX, gMaxY;
  51. short            gCurrentX, gCurrentY;
  52. short            gPixelColor;            /* Pixel value for offscreen line drawing */
  53. Boolean         gAtLineStart;            /* True at the first of the line */
  54. Boolean         gOnLand;                /* True when plotting land, else false */
  55. char*            gPixelBase;                /* Base of pixel store */
  56.  
  57.  
  58. /*
  59.     RandomDouble
  60.     
  61.     This function returns a random number between -1 and 1.
  62. */
  63. double RandomDouble(void)
  64. {
  65.     return (double)rand() / RAND_MAX;
  66. }
  67.  
  68.  
  69. /*
  70.     CalcSurface
  71.     
  72.     This is the main surface-generating routine. It generates a random
  73.     fractal surface by filling in the gPointArray array.
  74. */
  75. void CalcSurface(short level)
  76. {
  77.     short             i, j, length, incrby, sk;
  78.     float             power;
  79.     CursHandle         waitCursor;
  80.     long            startTicks;
  81.         
  82.     waitCursor = GetCursor(watchCursor);
  83.     if (waitCursor)
  84.         SetCursor(*waitCursor);              /* Show busy cursor */
  85.  
  86.     gTotalFractals++;
  87.     gFractalChanged = true;
  88.     startTicks = TickCount();
  89.     
  90.     gMaxX = 1 << level;
  91.     gMaxY = gMaxX / 2;
  92.     for (i = 0; i <= gMaxX; i++)           /* Clear the Array.  Use i & incrby as temps */
  93.     for (incrby = 0; incrby <= gMaxY; incrby++)
  94.         (*gPointArray)[i][incrby] = 0;
  95.  
  96.     for (i = 1; i <= level; i++) {
  97.         for (power = 1.0, j = 0; j < i; j++)
  98.             power *= 1.8;
  99.         length = 10000 / power;            /* = 10000/(1.8^i) */
  100.         incrby = gMaxX / (1 << i);         /* # of line segments in a side of the triangle */
  101.         sk = incrby * 2;
  102.         CalcXs(length, incrby, sk);
  103.         CalcYs(length, incrby, sk);
  104.         CalcDiagonals(length, incrby, sk);
  105.     }
  106.     
  107.     gTotalTickCount += TickCount() - startTicks;
  108.     InitCursor();                        /* Put back the arrow */
  109. }
  110.  
  111.  
  112. /*
  113.     CalcXs
  114.     
  115.     This function calculates the fractal values in the X direction.
  116.     It is called for each level and subdivides the existing edges
  117.     of the fractal to get the next level.
  118. */
  119. void CalcXs(short len, short incr, short sk)
  120. {
  121.     short             y, x;
  122.     short             d1, d2;
  123.  
  124.     for (y=0; y < gMaxX; y += sk) {
  125.         for (x = incr+y; x <= gMaxX; x += sk) {
  126.             d1 = GetZValue(x-incr, y);
  127.             d2 = GetZValue(x+incr, y);
  128.             SetZValue(((d1 + d2) >> 1) + (short)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
  129.         }
  130.     }
  131. }
  132.  
  133.  
  134. /*
  135.     CalcYs
  136.  
  137.     This function calculates the fractal values in the Y direction.
  138.     It is called for each level and subdivides the existing edges
  139.     of the fractal to get the next level.
  140. */
  141. void CalcYs(short len, short incr, short sk)
  142. {
  143.     short y, x;
  144.     short d1, d2;
  145.  
  146.     for (x = gMaxX; x >= 1; x -= sk)
  147.         for (y = incr; y <= x; y += sk) {
  148.             d1 = GetZValue(x, y + incr);
  149.             d2 = GetZValue(x, y - incr);
  150.             SetZValue(((d1 + d2) >> 1) + (short)(RandomDouble() * (len >> 1)) - (len >> 2), x, y);
  151.         }
  152. }
  153.  
  154.  
  155. /*
  156.     CalcDiagonals
  157.  
  158.     This function calculates the fractal values in the diagonal direction.
  159.     It is called for each level and subdivides the existing edges
  160.     of the fractal to get the next level.
  161. */
  162. void CalcDiagonals(short len, short incr, short sk)
  163. {
  164.     short             y, x;
  165.     short             d1, d2;
  166.         
  167.     for (x = 0; x < gMaxX; x += sk)
  168.     for (y = incr; y <= gMaxX - x; y += sk) {
  169.         d1 = GetZValue(x + y - incr, y - incr);
  170.         d2 = GetZValue(x + y + incr, y + incr);
  171.         SetZValue(((d1 + d2) >> 1) + (short)(RandomDouble() * (len >> 1)) - (len >> 2), x + y, y);
  172.     }
  173. }
  174.  
  175.  
  176. /*
  177.     GetZValue
  178.  
  179.     This function returns the Z value (i.e. the value stored in the
  180.     two-dimensional gPlotArray array. Because the fractal is triangular
  181.     and the array is square, we will store half the triange in the lower
  182.     part of the array the the other half in the upper part of the
  183.     array.
  184. */
  185. short GetZValue(short x, short y)
  186. {
  187.     if (y <= gMaxY)
  188.         return (*gPointArray)[x][y];
  189.     else
  190.         return (*gPointArray)[gMaxX - x][gMaxX + 1 - y];
  191. }
  192.  
  193.  
  194. /*
  195.     SetZValue
  196.  
  197.     This function saves the Z value (i.e. the value in the
  198.     two-dimensional gPlotArray array. Because the fractal is triangular
  199.     and the array is square, we will store half the triange in the lower
  200.     part of the array the the other half in the upper part of the
  201.     array.
  202. */
  203. void SetZValue(short d, short x, short y)
  204. {
  205.     if (y <= gMaxY)
  206.         (*gPointArray)[x][y] = d;
  207.     else
  208.         (*gPointArray)[gMaxX - x][gMaxX + 1 - y] = d;
  209. }
  210.  
  211.  
  212. /*
  213.     PlotData
  214.     
  215.     Our window is already open at this point, and it is cleared.
  216.     All we have to do now is fill it. This function draws the 
  217.     2D projection of the triangular database on the screen.
  218. */
  219. void PlotData(void)
  220. {
  221.     short             xindex, yindex;
  222.  
  223.     gOnLand = true;                                        /* On land to start */
  224.  
  225.     for (xindex = 0; xindex <= gMaxX; xindex++) {        /* Plot along X axis */
  226.         gAtLineStart = true;
  227.         for (yindex = 0; yindex <= xindex; yindex++)
  228.             DoPlot(xindex, yindex);
  229.     }
  230.     
  231.     for (yindex = 0; yindex <= gMaxX; yindex++) {        /* Plot along Y axis */
  232.         gAtLineStart = true;
  233.         for (xindex = yindex; xindex <= gMaxX; xindex++)
  234.             DoPlot(xindex, yindex);
  235.     }
  236.     
  237.     for (xindex = 0; xindex <= gMaxX; xindex++) {        /* Plot along the diagonal */
  238.         gAtLineStart = true;
  239.         for (yindex = 0; yindex <= gMaxX - xindex; yindex++)
  240.             DoPlot(xindex + yindex, yindex);
  241.     }
  242. }
  243.  
  244.  
  245. /*
  246.     DoPlot
  247.     
  248.     This function plots a single line or point from the current X and
  249.     Y value to the new X and Y value specified.
  250. */
  251. void DoPlot(short xindex, short yindex)
  252. {
  253.     short        xcoord, ycoord, zcoord;
  254.  
  255.     gPixelBase = (char*)GetPixBaseAddr(gOffscreenPixMap);
  256.  
  257.     zcoord = GetZValue(xindex, yindex);
  258.     ycoord = ScaleValue(yindex, 10000, gMaxX);
  259.     xcoord = ScaleValue(xindex, 10000, gMaxX) - ycoord/2;
  260.     if (gContourType == kStyleWater)
  261.         SeaLevel(&xcoord, &ycoord, &zcoord);
  262.     PlotTo(xcoord, ycoord, zcoord);
  263. }
  264.  
  265.  
  266. /*
  267.     SeaLevel
  268.     
  269.     This function is used to plot lines when using the “foothills
  270.     with water” mode. It determines whether a line goes under
  271.     water at any point. If it does, it simply draws a point
  272.     to represent the water.
  273. */
  274. void SeaLevel(short *newX, short *newY, short *newZ)
  275. {
  276.     static short     oldX, oldY, oldZ;            /* The starting point for the next call */
  277.     short             waterX, waterY, waterZ;     /* Where the vector hits the waterline. */
  278.     float             scratch;
  279.  
  280.     if (gAtLineStart) {                        /* If at the beginning of the line */
  281.         if ((oldZ = *newZ) < 0) {            /*  and if we’re underwater */
  282.             SetLineColor(blueColor);
  283.             gOnLand = false;
  284.             *newZ = 0;                        /* Clip to the waterline */
  285.         }
  286.         else {
  287.             SetLineColor(blackColor);
  288.             gOnLand = true;                    /* Otherwise we’re on land from the start */
  289.         }
  290.     }
  291.     else {                                    /* Else we’re in the middle of a line and */
  292.         if (oldZ > 0 && *newZ > 0) {        /* Start & end points both above water.. */
  293.             oldZ = *newZ;
  294.         }
  295.         else if (oldZ < 0 && *newZ < 0) {    /* Start & end points both under water... */
  296.             oldZ = *newZ;
  297.             *newZ = 0;                        /* Clip at the waterline */
  298.         }
  299.         else {                                /* We’re now crossing the waterline, so calculate */
  300.                                             /*  the exact point where it dives under */
  301.             scratch = (float) (*newZ) / (*newZ - oldZ);                /* Proportion of the line that’s */
  302.             waterX = (short) ((oldX - *newX) * scratch) + *newX;    /*  below the water */
  303.             waterY = (short) ((oldY - *newY) * scratch) + *newY;
  304.             waterZ = 0;
  305.  
  306.             PlotTo(waterX, waterY, waterZ);    /* Draw to the waterline first */
  307.             
  308.             /* The plot from the waterline to the endpoint in the new color is done elsewhere */
  309.             if (*newZ > 0) {                /* Emerging from the water */
  310.                 SetLineColor(blackColor);
  311.                 gOnLand = true;
  312.                 oldZ = *newZ;
  313.             }
  314.             else {                            /* Diving into the water. */
  315.                 SetLineColor(blueColor);
  316.                 gOnLand = false;
  317.                 oldZ = *newZ;
  318.                 *newZ = 0;
  319.             }
  320.         }
  321.     }
  322.     oldX = *newX;                            /* Save the real endpoint of the vector */
  323.     oldY = *newY;                            /*  to use as the start of the next call */
  324. }
  325.  
  326.  
  327. /*
  328.     ScaleValue
  329.     
  330.     Computes base * numer / denom with long intermediate
  331. */
  332. short ScaleValue(short base, short numer, short denom)
  333. {
  334.     long            temp;
  335.  
  336.     temp = (long) base * (long) numer;
  337.     temp /= (long) denom;
  338.     return (short) temp;
  339. }
  340.  
  341.  
  342. /*
  343.     PlotTo
  344.     
  345.     This function converts a 3-D line to a 2-D line and plots it
  346. */
  347. void PlotTo(short x, short y, short z)
  348. {
  349.     Rotate(&x, &y);         /* Rotate 30 deg. towards Y in the XY plane */
  350.     TiltDown(&x, &z);       /* Tip 36 deg. down in the ZX plane */
  351.     x /= 25;                /* Scale 10K to 400. */
  352.     y /= 25;
  353.     z /= 25;
  354.     DrawLine(y, z);         /* Show the YZ planar projection. */
  355. }
  356.  
  357.  
  358. /*
  359.     Rotate
  360.     
  361.     This function rotates a point in the XY plane a + 30 degress.
  362. */ 
  363. void Rotate(short *x, short *y)
  364. {
  365.     Cordic(x, y, 5, 17);
  366. }
  367.  
  368.  
  369. /*
  370.     TiltDown
  371.     
  372.     This function rotates a point in the XZ plane a + or - 36 degress.
  373. */
  374. void TiltDown(short *x, short *z)
  375. {
  376.     Cordic(x, z, 5, (gContourType == kStyleMountains) ? 20 : -20);
  377. }
  378.  
  379.  
  380. /*
  381.     DrawLine
  382.     
  383.     This function draws a line from the last endpoint
  384. */
  385. void DrawLine(short x, short y)
  386. {
  387.     x += x/10 + 10;                         /* Compute x1.1 + tiny offset */
  388.     if (gContourType == kStyleMountains)
  389.             y = 220 - y;                    /* Move the baseline for mountains */
  390.     else
  391.             y = 80 - y;
  392.  
  393.     if (gAtLineStart || !gOnLand)            /* Only a point then */
  394.         ScaledMoveTo(x, y);
  395.  
  396.     ScaledLineTo(x, y);
  397.     gAtLineStart = false;
  398. }
  399.  
  400.  
  401. /*
  402.     Cordic
  403.     
  404.     This function spins the XY vector ‘count’ steps to the left 
  405.     using a CORDIC algorithm with a shift factor of ‘scale.’
  406.     Rotates atan(1/(2^scale)) degrees/step (e.g. scale of 5 is 
  407.     1.79 deg/step;  4 = 3.57 d/s...)
  408.     
  409.     *x and *y should be large for accuracy.
  410. */
  411. void Cordic(short *x, short *y, short scale, short count)      
  412. {
  413.     short            tempX, tempY;
  414.  
  415.     tempX = *x;
  416.     tempY = *y;
  417.     if (count > 0)                        /* Positive count is CCW (left) */
  418.         for (; count; count--) {
  419.             tempX -= (tempY >> scale);
  420.             tempY += (tempX >> scale);
  421.         }
  422.     else                                /* Negative is CW (right) */
  423.         for (; count; count++) {
  424.             tempX += (tempY >> scale);
  425.             tempY -= (tempX >> scale);
  426.         }
  427.     *x = tempX;
  428.     *y = tempY;
  429. }
  430.  
  431.  
  432. /*
  433.     ScaledMoveTo
  434.     
  435.     This function performs a scaled MoveTo by scaling the given
  436.     point from MacPlus screen coordinates to the size of the
  437.     current main window.
  438. */
  439. void ScaledMoveTo(short x, short y)
  440. {
  441.     short scaledX, scaledY;
  442.     
  443.     scaledX = (long)x * (long)kNewScreenX / kOriginalScreenX;
  444.     scaledY = (long)y * (long)kNewScreenY / kOriginalScreenY;
  445.  
  446.     MoveToOffscreen(scaledX, scaledY);
  447. }
  448.  
  449.  
  450. /*
  451.     ScaledLineTo
  452.  
  453.     This function performs a scaled LineTo by scaling the given
  454.     point from MacPlus screen coordinates to the size of the
  455.     current main window.
  456. */
  457. void ScaledLineTo(short x, short y)
  458. {
  459.     short scaledX, scaledY;
  460.  
  461.     scaledX = (long)x * (long)kNewScreenX / kOriginalScreenX;
  462.     scaledY = (long)y * (long)kNewScreenY / kOriginalScreenY;
  463.  
  464.     LineToOffscreen(scaledX, scaledY);
  465. }
  466.  
  467.  
  468. /*
  469.     SetLineColor
  470. */
  471. void SetLineColor(short colorCode)
  472. {
  473.     RGBColor        curColor;
  474.  
  475.     ForeColor(colorCode);
  476.     GetForeColor(&curColor);
  477.  
  478.     gPixelColor = Color2Index(&curColor);
  479. }
  480.  
  481.  
  482. /*
  483.     MoveToOffscreen
  484. */
  485. void MoveToOffscreen(short x, short y)
  486. {
  487.     gCurrentX = x;
  488.     gCurrentY = y;
  489. }
  490.  
  491.  
  492. /*
  493.     LineToOffscreen
  494. */
  495. void LineToOffscreen(short x, short y)
  496. {
  497.     if (abs(y - gCurrentY) > abs(x - gCurrentX)) {
  498.         if (y < gCurrentY)
  499.             LineYOffscreen(x, y, gCurrentX, gCurrentY);
  500.         else
  501.             LineYOffscreen(gCurrentX, gCurrentY, x, y);
  502.     }
  503.     else {
  504.         if (x < gCurrentX)
  505.             LineXOffscreen(x, y, gCurrentX, gCurrentY);
  506.         else
  507.             LineXOffscreen(gCurrentX, gCurrentY, x, y);
  508.     }
  509.     
  510.     gCurrentX = x;
  511.     gCurrentY = y;
  512. }
  513.  
  514.  
  515. /*
  516.     LineXOffscreen
  517.  
  518.     Draws lines with a slope between -1 and 1
  519. */
  520. void LineXOffscreen(short startX, short startY, short endX, short endY)
  521. {
  522.     short            currentX;
  523.     float            slope, currentY, newY;
  524.     float            yRowIncrement;
  525.     char*            pixelAddress;
  526.     long            deltaY;
  527.     
  528.     if (endX == startX)
  529.         slope = 0;
  530.     else
  531.         slope = (float)(endY - startY) / (float)(endX - startX);
  532.  
  533.     pixelAddress = gPixelBase + startX;
  534.     yRowIncrement = (short)((*gOffscreenPixMap)->rowBytes & 0x7FFF);
  535.     pixelAddress += (unsigned long)(startY * yRowIncrement);
  536.     currentY = startY + 0.5;
  537.     
  538.     for (currentX = startX; currentX <= endX; currentX++) {
  539.         *pixelAddress++ = gPixelColor;
  540.         newY = currentY + slope;
  541.         pixelAddress += (long)(yRowIncrement * ((long)(newY) - (long)(currentY)));
  542.         currentY = newY;
  543.     }
  544. }
  545.  
  546.  
  547. /*
  548.     LineYOffscreen
  549.  
  550.     Draws lines with a slope <= -1 or >= 1
  551. */
  552. void LineYOffscreen(short startX, short startY, short endX, short endY)
  553. {
  554.     short            currentY;
  555.     float            slope, currentX, newX;
  556.     unsigned long    yRowIncrement;
  557.     char*            pixelAddress;
  558.     
  559.     if (endY == startY)
  560.         slope = 0;
  561.     else
  562.         slope = (float)(endX - startX) / (float)(endY - startY);
  563.  
  564.     pixelAddress = gPixelBase + startX;
  565.     yRowIncrement = (*gOffscreenPixMap)->rowBytes & 0x7FFF;
  566.     pixelAddress += (unsigned long)(startY * yRowIncrement);
  567.     currentX = startX + 0.5;
  568.     
  569.     for (currentY = startY; currentY <= endY; currentY++) {
  570.         *pixelAddress = gPixelColor;
  571.         newX = currentX + slope;
  572.         pixelAddress += yRowIncrement + (long)(newX) - (long)(currentX);
  573.         currentX = newX;
  574.     }
  575. }
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.